package com.xiaoshuidi.cloud.module.rooms.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.oss.core.OosFileService;
import com.xiaoshuidi.cloud.module.rooms.controller.admin.pricing.vo.*;
import com.xiaoshuidi.cloud.module.rooms.controller.admin.roomel.vo.RoomelUpdateReqVO;
import com.xiaoshuidi.cloud.module.rooms.convert.rentalspace.RentalSpaceConvert;
import com.xiaoshuidi.cloud.module.rooms.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.rooms.enums.PricingRecordsType;
import com.xiaoshuidi.cloud.module.rooms.enums.RentSpaceRentStatusEnum;
import com.xiaoshuidi.cloud.module.rooms.enums.RentStatusEnum;
import com.xiaoshuidi.cloud.module.rooms.framework.config.ConfigValues;
import com.xiaoshuidi.cloud.module.rooms.mq.listener.HousePricingListener;
import com.xiaoshuidi.cloud.module.rooms.mq.producer.RoomEsProducer;
import com.xiaoshuidi.cloud.module.rooms.pojo.*;
import com.xiaoshuidi.cloud.module.rooms.repository.*;
import com.xiaoshuidi.cloud.module.rooms.service.IRoomPricingService;
import com.xiaoshuidi.cloud.module.system.api.oss.OosApi;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author Feng
 * @date 2023/5/16
 */
@Service
@RequiredArgsConstructor
public class RoomPricingServiceImpl implements IRoomPricingService {

    private final RoomPricingRecordsRepository pricingRecordsRepository;
    private final RoomLayoutRepository layoutRepository;
    private final RoomHouseRepository roomHouseRepository;
    private final RentalSpaceRepository rentalSpaceRepository;
    private final ConfigValues configValues;
    private final ApartmentRepository apartmentRepository;
    private final RoomEsProducer roomEsProducer;
    private final OosFileService oosFileService;
    private final RoomStateRecordRepository roomStateRecordRepository;
    private final OosApi oosApi;

    @Override
    @Transactional
    public boolean setLayoutPricing(SetLayoutPricingReq req) {
        //修改房型价格,同时修改改房型下所有房源的价格,不需要关注房态
        RoomLayout roomLayout = layoutRepository.getById(req.getLayoutId());
        Assert.isTrue(ObjectUtil.isNotEmpty(roomLayout), "该房型不存在");
        List<RoomPricingRecords> recordsList = new ArrayList<>();
        Double beforeMonthRental = roomLayout.getMonthRental();
        Double afterMonthRental = req.getMonthRental();
        roomLayout.setMonthRental(req.getMonthRental());
        RoomPricingRecords layoutPricingRecords = setRoomPricingRecords(PricingRecordsType.LAYOUT.getCode(), beforeMonthRental, afterMonthRental, roomLayout.getId());
        recordsList.add(layoutPricingRecords);
        layoutRepository.updateById(roomLayout);
        //获取该房型下的所有房源
        List<RoomHouse> houseList = roomHouseRepository.listByApartmentIdAndLayoutId(roomLayout.getApartmentId(), roomLayout.getId());
        if (CollectionUtil.isNotEmpty(houseList)) {
            List<RoomHouse> updateRoomHouseList = new ArrayList<>();
            List<RoomelUpdateReqVO> updateReqVOList = new ArrayList<>();
            houseList.forEach(s -> {
                Double houseBefore = s.getMonthRental();
                RoomHouse roomHouse = new RoomHouse();
                roomHouse.setMonthRental(afterMonthRental);
                roomHouse.setId(s.getId());
                updateRoomHouseList.add(roomHouse);

                //ES保存数据
                RoomelUpdateReqVO roomelUpdateReqVO = new RoomelUpdateReqVO();
                roomelUpdateReqVO.setPrice(afterMonthRental);
                roomelUpdateReqVO.setId(s.getId());
                updateReqVOList.add(roomelUpdateReqVO);

                RoomPricingRecords houseRecords = setRoomPricingRecords(PricingRecordsType.HOUSE.getCode(), houseBefore, afterMonthRental, s.getId());
                recordsList.add(houseRecords);
            });
            roomHouseRepository.updateBatchById(updateRoomHouseList);
            // 更新ES房源数据
            roomEsProducer.updateBatchRoomEl(updateReqVOList);

        }
        pricingRecordsRepository.saveBatch(recordsList);
        return true;
    }

    @Override
    public PageResult<RoomHousePricingPageResp> roomHousePricingPage(RoomHouseRicingPageReq req) {
        Page<RoomHousePricingPageResp> page = roomHouseRepository.pricingPage(req.getApartmentId(), req.getLayoutId(), req.getHouseNo(), req.getIsConcentrated(), req.getPageSize(), req.getPageNo());
        PageResult<RoomHousePricingPageResp> result = new PageResult<>(page.getRecords(), page.getTotal());
        return result;
    }

    @Override
    @Transactional
    public Boolean setHousePricing(SetHousePricingReq req) {
        Long houseId = req.getHouseId();
        RoomHouse house = roomHouseRepository.getById(houseId);
        Assert.isTrue(ObjectUtil.isNotEmpty(house), "该房源不存在");
        if (house.getMonthRental() != null && house.getMonthRental().equals(req.getMonthRental())) {
            return true;
        }
        RoomHouse updateHouse = new RoomHouse();
        updateHouse.setId(houseId);
        updateHouse.setMonthRental(req.getMonthRental());

        //ES保存数据
        RoomelUpdateReqVO roomelUpdateReqVO = new RoomelUpdateReqVO();
        roomelUpdateReqVO.setPrice(req.getMonthRental());
        roomelUpdateReqVO.setId(houseId);

        //创建修改定价记录
        RoomPricingRecords pricingRecords = setRoomPricingRecords(PricingRecordsType.HOUSE.getCode(), house.getMonthRental(), req.getMonthRental(), houseId);
        roomHouseRepository.updateById(updateHouse);
        pricingRecordsRepository.save(pricingRecords);
        // 更新ES数据
        roomEsProducer.updateRoomEl(roomelUpdateReqVO);
        return true;
    }

    @Override
    public PageResult<RentalSpacePricingPageResp> rentalSpacePricingPage(RentalSpacePricingPageReq req) {
        Page<RoomRentalSpace> page = rentalSpaceRepository.pricingPage(req.getApartmentId(), req.getSpaceName(), req.getType(), req.getPageSize(), req.getPageNo());
        List<RentalSpacePricingPageResp> respList = RentalSpaceConvert.INSTANCE.convert(page.getRecords());
        PageResult<RentalSpacePricingPageResp> result = new PageResult<>(respList, page.getTotal());
        return result;
    }

    @Override
    public Boolean setRentalSpacePricing(SetRentalSpacePricingReq req) {
        Long spaceId = req.getId();
        RoomRentalSpace space = rentalSpaceRepository.getById(spaceId);
        Assert.isTrue(ObjectUtil.isNotEmpty(space), "该空间不存在");
        if (space.getMonthRental() != null && space.getMonthRental().equals(req.getMonthRental())) {
            return true;
        }
        RoomRentalSpace updateSpace = new RoomRentalSpace();
        updateSpace.setId(spaceId);
        updateSpace.setMonthRental(req.getMonthRental());
        //创建修改定价记录
        RoomPricingRecords pricingRecords = setRoomPricingRecords(PricingRecordsType.SPACE.getCode(), space.getMonthRental(), req.getMonthRental(), spaceId);
        rentalSpaceRepository.updateById(updateSpace);
        pricingRecordsRepository.save(pricingRecords);
        // 更新空间ES数据 - 空间功能取消
        return true;
    }

    @Override
    public HousePricingExportResp housePricingExport(HousePricingExportReq req) {
        long count = roomHouseRepository.pricingCount(req.getApartmentId(), null, null, req.getIsConcentrated());
        if (count <= 0) {
            throw new ServiceException(ErrorCodeConstants.HOUSE_NOT_EXISTS);
        }
        int pageSize = 5000;
        int totalPage = (int) count / pageSize;
        if (count % pageSize != 0) {
            totalPage++;
        }
        Apartment apartment = apartmentRepository.getById(req.getApartmentId());
        String fileName = configValues.getNfsPath() + File.separator + apartment.getName() + "房源价格.xlsx";
        ExcelWriter excelWriter = EasyExcel.write(fileName, HousePricingExportVo.class).build();
        WriteSheet sheet = EasyExcel.writerSheet("sheet1").build();
        for (int i = 1; i <= totalPage; i++) {
            Page<RoomHousePricingPageResp> page = roomHouseRepository.pricingPage(req.getApartmentId(), null, null, req.getIsConcentrated(), pageSize, i);
            List<RoomHousePricingPageResp> records = page.getRecords();
            //查询房态
            List<Long> houseIds = records.stream().map(s -> s.getId()).collect(Collectors.toList());
            List<RoomStateRecord> stateRecordList = roomStateRecordRepository.getListByRoomIdAndIsCurrentState(houseIds);
            Map<Long, List<RoomStateRecord>> stateMap = stateRecordList.stream().collect(Collectors.groupingBy(RoomStateRecord::getRoomId));
            List<HousePricingExportVo> vos = records.stream().map(s -> {
                HousePricingExportVo vo = new HousePricingExportVo();
                if (req.getIsConcentrated()) {
                    vo.setHouseNo(String.format("%s栋%s", s.getBuildingNo(), s.getHouseName()));
                } else {
                    vo.setHouseNo(String.format("%s%s栋%s单元%s", s.getArea(), s.getBuildingNo(), s.getUnitNo(), s.getHouseName()));
                }
                List<RoomStateRecord> roomStateRecords = stateMap.get(s.getId());
                if (CollectionUtil.isNotEmpty(roomStateRecords)) {
                    String state = roomStateRecords.stream().map(record -> RentStatusEnum.getName(record.getState())).collect(Collectors.joining("|"));
                    vo.setRentStatus(state);
                }
                vo.setMonthRental(s.getMonthRental());
                return vo;
            }).collect(Collectors.toList());
            excelWriter.write(vos, sheet);
        }
        excelWriter.finish();
        //上传到oos返回URL
        String url = oosFileService.oosUploadFile(new File(fileName));
        HousePricingExportResp resp = new HousePricingExportResp();
        resp.setUrl(url);
        resp.setFileName(apartment.getName() + "房源价格.xlsx");
        return resp;
    }

    @Override
    public HousePricingExportResp housePricingTemplateExport(HousePricingExportReq req) {
        long count = roomHouseRepository.pricingCount(req.getApartmentId(), null, null, req.getIsConcentrated());
        if (count <= 0) {
            throw new ServiceException(ErrorCodeConstants.HOUSE_NOT_EXISTS);
        }
        int pageSize = 5000;
        int totalPage = (int) count / pageSize;
        if (count % pageSize != 0) {
            totalPage++;
        }
        Apartment apartment = apartmentRepository.getById(req.getApartmentId());
        String fileName = configValues.getNfsPath() + File.separator + apartment.getName() + "房源价格导入模板.xlsx";
        ExcelWriter excelWriter = EasyExcel.write(fileName, HousePricingTemplateVo.class).build();
        WriteSheet sheet = EasyExcel.writerSheet("sheet1").build();
        for (int i = 1; i <= totalPage; i++) {
            Page<RoomHousePricingPageResp> page = roomHouseRepository.pricingPage(req.getApartmentId(), null, null, req.getIsConcentrated(), pageSize, i);
            List<RoomHousePricingPageResp> records = page.getRecords();
            List<HousePricingTemplateVo> vos = records.stream().map(s -> {
                HousePricingTemplateVo vo = new HousePricingTemplateVo();
                if (req.getIsConcentrated()) {
                    vo.setHouseNo(String.format("%s栋%s", s.getBuildingNo(), s.getHouseName()));
                } else {
                    vo.setHouseNo(String.format("%s%s栋%s单元%s", s.getArea(), s.getBuildingNo(), s.getUnitNo(), s.getHouseName()));
                }
                vo.setNo(s.getNo());
                vo.setMonthRental(s.getMonthRental());
                return vo;
            }).collect(Collectors.toList());
            excelWriter.write(vos, sheet);
        }
        excelWriter.finish();
        //上传到oos返回URL
        String url = oosFileService.oosUploadFile(new File(fileName));
        HousePricingExportResp resp = new HousePricingExportResp();
        resp.setUrl(url);
        resp.setFileName(apartment.getName() + "房源价格导入模板.xlsx");
        return resp;
    }

    @Override
    public String spacePricingExport(RentalSpacePricingExportReq req) {
        long count = rentalSpaceRepository.pricingCount(req.getApartmentId(), null, req.getType());
        if (count <= 0) {
            throw new ServiceException(ErrorCodeConstants.SPACE_NOT_EXISTS);
        }
        int pageSize = 5000;
        int totalPage = (int) count / pageSize;
        if (count % pageSize != 0) {
            totalPage++;
        }
        Apartment apartment = apartmentRepository.getById(req.getApartmentId());
        String fileName = configValues.getNfsPath() + File.separator + apartment.getName() + "租赁空间价格.xlsx";
        ExcelWriter excelWriter = EasyExcel.write(fileName, SpacePricingExportVo.class).build();
        WriteSheet sheet = EasyExcel.writerSheet("sheet1").build();
        for (int i = 1; i <= totalPage; i++) {
            Page<RoomRentalSpace> page = rentalSpaceRepository.pricingPage(req.getApartmentId(), null, req.getType(), pageSize, i);
            List<RoomRentalSpace> records = page.getRecords();
            List<SpacePricingExportVo> vos = records.stream().map(s -> {
                SpacePricingExportVo vo = new SpacePricingExportVo();
                vo.setName(s.getName());
                vo.setRentStatus(RentSpaceRentStatusEnum.getName(s.getRentStatus()));
                vo.setMonthRental(s.getMonthRental());
                return vo;
            }).collect(Collectors.toList());
            excelWriter.write(vos, sheet);
        }
        excelWriter.finish();
        // 上传到oos返回URL - 空间功能取消
        return null;
    }

    @Override
    public Boolean housePricingImport(Long apartmentId, Boolean isConcentrated, String fileUrl) {
        //根据fileUrl读取oos文件
        try (InputStream is = new ByteArrayInputStream(HttpUtil.downloadBytes(fileUrl))) {
            EasyExcel.read(is, HousePricingTemplateVo.class, new HousePricingListener(roomHouseRepository, roomEsProducer, pricingRecordsRepository, apartmentId, isConcentrated)).sheet().doRead();
        } catch (IOException e) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "文件不存在");
        } catch (ExcelDataConvertException e) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "数据格式不正确");
        }
        return true;
    }

    public RoomPricingRecords setRoomPricingRecords(String type, Double beforeMonthRental, Double afterMonthRental, Long mappingId) {
        RoomPricingRecords roomPricingRecords = new RoomPricingRecords();
        roomPricingRecords.setType(type)
                .setBeforeMonthRental(beforeMonthRental)
                .setAfterMonthRental(afterMonthRental)
                .setMappingId(mappingId);
        return roomPricingRecords;
    }
}
